/**
 * 
 */
package com.xpec.c4.service.module;

import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.xpec.c4.game.time.TimeSys;
import com.xpec.c4.game.utility.GameUtility;
import com.xpec.c4.message.ConstantCode;
import com.xpec.c4.message.MessageTypes;
import com.xpec.c4.service.contexts.Contexts;
import com.xpec.c4.service.module.task.TaskNetMessage;
//import com.xpec.c4.service.module.mobile.MobileModule;
import com.xpec.c4.service.module.task.TaskObject;


/**
 * 執行緒區間
 * 
 * @author Eric_Wang
 *
 */
public class ThreadSection implements Runnable {
	/**
	 * task 執行時間超過這個時間就產生警告 log
	 */
	public static final long TASK_EXECUTE_WARN_TIME = 1500;

	/**
	 * Log管理器
	 */
	private static final Log log = LogFactory.getLog(ThreadSection.class);

	/**
	 * 若此為Module所屬的主ThreadSection 則此變數不為null
	 */
	private BasicServiceModule ownerModule;
	
	/**
	 * 父執行緒區間
	 */
	private ThreadSection parentSection;
	
	/**
	 * 存放等待處理的Task
	 */
	private Queue<TaskObject> taskQueue = null;

	/**
	 * 
	 */
	private Lock threadLock = new ReentrantLock();
	private Condition enterSectionQueueCondition = threadLock.newCondition();
	private Condition returnSectionQueueCondition = threadLock.newCondition();
	private Object mainThreadSignal = new Object();
	
	/**
	 * 從父ThreadSection進入 等待執行的Thread
	 */
	private ConcurrentLinkedQueue<Thread> enterSectionQueue = new ConcurrentLinkedQueue<Thread>();
	
	/**
	 * 從子ThreadSection返回 等待執行的Thread
	 */
	private ConcurrentLinkedQueue<Thread> returnSectionQueue = new ConcurrentLinkedQueue<Thread>();
	
	/**
	 * 是否為單一執行緒
	 */
	private boolean singleThread = true;

	/**
	 * 單執行緒模式的主線程
	 */
	private Thread mainThread = null;

	/**
	 * 執行緒結束旗標
	 */
	public static enum MODULE_STATE
	{
		RUNNING,
		WAIT_TO_CLOSE,
		CLOSED,
	}
	
	private volatile MODULE_STATE state = MODULE_STATE.RUNNING;
	
	/**
	 * 正在子執行緒區間執行的執行緒數目
	 */
	private int syncMultiThreadCount = 0;
	
	public boolean isTermineted()
	{
		//子區間如果是單執行緒的狀況下，沒被呼叫過是不會有執行緒去切換的
		if(mainThread == null)
		{
			if(singleThread)
			{
				if(state == MODULE_STATE.WAIT_TO_CLOSE)
				{
					state = MODULE_STATE.CLOSED;
				}
			}
			else
			{
				//如果是多執行緒更不會有mainThread，只能檢查目前還有沒有人在子區間等待
				if(getMultiThreadCount() == 0)
				{
					if(state == MODULE_STATE.WAIT_TO_CLOSE)
					{
						state = MODULE_STATE.CLOSED;
					}
				}
			}
			
		}
		return state == MODULE_STATE.CLOSED;
	}
	
	/**
	 * 理论上大部分的Map容器还是维持在Global形式下运作
	 * 只是让event contexts在线程里独自运作
	 */
	private Contexts contexts;

	private boolean terminated;



	////////////////////////////////////////////////////////////////////////////////////////////////
	/**
	 * Module所屬的主ThreadSection使用此建構式
	 * 主ThreadSection必為singleThread模式
	 * @param ownerModule
	 * @param taskQueue
	 */
	public ThreadSection(BasicServiceModule ownerModule, Queue<TaskObject> taskQueue) {
		this.ownerModule = ownerModule;
		this.taskQueue = taskQueue;
	}
	
	/**
	 * 子ThreadSection使用此建構式
	 * @param parentSection 父執行緒區間
	 */
	public ThreadSection(ThreadSection parentSection) {
		this(parentSection, true);
	}
	
	/**
	 * 子ThreadSection使用此建構式 可指定執行緒模式
	 * @param parentSection 父執行緒區間
	 * @param singleThread 執行緒模式 
	 * 						true:單執行緒模式(同時間只會有單一執行緒執行)
	 * 						false:多執行緒模式 
	 */
	public ThreadSection(ThreadSection parentSection, boolean singleThread) {
		this.parentSection = parentSection;
		this.singleThread = singleThread;
	}
	
	public void shutdown(){
		state = MODULE_STATE.WAIT_TO_CLOSE;
		notifyMainThread();
	}
	
	/**
	 * 開啟執行緒並執行
	 */
	public void createMainThread() {
		if (ownerModule == null) return;
		
		if (mainThread == null) {
//			mainThread =  new Thread(this);
//			mainThread.setName("c4_" + ownerModule.getModuleName() + "_" + mainThread.getId());
//			mainThread.start();
			
			ThreadPool.getInstance().execute(this);
		}
	}
	
	/**
	 * 喚醒執行緒
	 */
	protected void notifyMainThread(){
		synchronized(mainThreadSignal) {
			mainThreadSignal.notify();
		}
	}
	
	/**
	 * 標記增加多執行緒數目
	 */
	private synchronized void addMultiThreadCount()
	{
		this.syncMultiThreadCount++;
	}
	
	/**
	 * 標記減少多執行緒數目
	 */
	private synchronized void subMultiThreadCount()
	{
		this.syncMultiThreadCount--;
	}
	
	/**
	 * 獲得目前多執行緒數目
	 * @return
	 */
	private synchronized int getMultiThreadCount() 
	{
		return syncMultiThreadCount;
	}
	
	/**
	 * 進入此區間
	 */
	public void enter() {
		if (parentSection == null) return;
		
		log.info("ThreadSection " + this.getClass().getSimpleName() + " Enter");

		//原區間若是單執行緒模式 mainThread要找替代者
		if (parentSection.singleThread == true) {
			parentSection.threadLock.lock();
			try {
				if (parentSection.returnSectionQueue.isEmpty() == false) {
					parentSection.mainThread = parentSection.returnSectionQueue.poll();
					parentSection.returnSectionQueueCondition.signal();
				}
				else if (parentSection.enterSectionQueue.isEmpty() == false) {
					parentSection.mainThread = parentSection.enterSectionQueue.poll();
					parentSection.enterSectionQueueCondition.signal();
				}
				else {
					parentSection.mainThread = null;
					//Module的主ThreadSection才開新執行緒
					if (parentSection.ownerModule != null) {
						parentSection.createMainThread();
					}
				}
			}
			finally {
				parentSection.threadLock.unlock();
			}
		}
		
		//進此區間執行
		if (singleThread == true) {
			threadLock.lock();
			try {
				if (mainThread == null) {
					mainThread = Thread.currentThread();
				}
				else {
					enterSectionQueue.add(Thread.currentThread());
					enterSectionQueueCondition.await();
				}
			}
			catch(Throwable e) {
				log.error("Enter ThreadSection error!" , e );
			}
			finally {
				threadLock.unlock();
			}
		}
		else
		{
			addMultiThreadCount();
		}
		
		log.info("ThreadSection " + this.getClass().getSimpleName() + " Enter and [Run]");
	}
	
	/**
	 * 離開此區間
	 */
	public void exit() {
		if (parentSection == null) return;
		
		log.info("ThreadSection " + this.getClass().getSimpleName() + " Exit");
		
		//此區間若為單執行緒則mainThread要找替代者
		if (singleThread == true) {
			if (mainThread != Thread.currentThread()) return;
			threadLock.lock();
			try {
				if (returnSectionQueue.isEmpty() == false) {
					mainThread = returnSectionQueue.poll();
					returnSectionQueueCondition.signal();
				}
				else if (enterSectionQueue.isEmpty() == false) {
					mainThread = enterSectionQueue.poll();
					enterSectionQueueCondition.signal();
				}
				else {
					mainThread = null;
				}
			}
			finally {
				threadLock.unlock();
			}
		}
		else
		{
			subMultiThreadCount();
		}
		
		//回父區間執行
		if (parentSection.singleThread == true) {
			parentSection.threadLock.lock();
			try {
				if (parentSection.mainThread == null) {
					parentSection.mainThread = Thread.currentThread();
				}
				else {
					parentSection.returnSectionQueue.add(Thread.currentThread());
					parentSection.notifyMainThread();
					parentSection.returnSectionQueueCondition.await();
				}
			}
			catch(Throwable e) {
				log.error("Exit ThreadSection error!" , e );
			}
			finally {
				parentSection.threadLock.unlock();
			}
		}
		
		log.info("ThreadSection " + this.getClass().getSimpleName() + " Exit and [Run]");
	}

	/**
	 * 執行緒迴圈
	 */
	@Override
	public void run() {
		mainThread = Thread.currentThread();
		mainThread.setName("c4_" + ownerModule.getModuleName() + "_" + mainThread.getId());
		
		//long startTime, endTime, operatorTime;
		//String logTitle;
		// 這个要等線程建立好才有数值(tid)
		contexts = new Contexts(ownerModule);
		
		boolean threadDone = false;
		while(true) {

			try {
				
				while (returnSectionQueue.isEmpty() == false || taskQueue.isEmpty() == false) 
				{
					if(state == MODULE_STATE.WAIT_TO_CLOSE || state == MODULE_STATE.CLOSED)
					{
						return;
					}
					//從子區間返回的執行緒優先
					threadLock.lock();
					try {
						if (returnSectionQueue.isEmpty() == false) {
							//替換回主執行緒
							mainThread = returnSectionQueue.poll();
							log.info("MainThread replace :" + mainThread.getName());
							//喚醒執行緒(signal預設會依await順序激發)
							returnSectionQueueCondition.signal();
							
							//讓自己結束
							threadDone = true;
							break;
						}
						else {

						}
					} catch (Exception e) {
						if (log.isErrorEnabled()) {
							log.error(GameUtility.getCurMethodName() + ": catch error 1", e);
						}
					} finally {
						threadLock.unlock();
					}
					
					//從taskQueue取得待執行的任務執行
					TaskObject taskObj = taskQueue.poll();
					//做了就扣掉
					ownerModule.getTaskCounter().decrementAndGet();

					if(taskObj != null){						
						try {
							long execBeginTime = TimeSys.currentTimeMills();
							
							taskObj.procTask();
							
							long spendTime = TimeSys.currentTimeMills() - execBeginTime;
							if (spendTime > ThreadSection.TASK_EXECUTE_WARN_TIME) {
								if (log.isErrorEnabled()) {
									StringBuilder sb = new StringBuilder("");
									if (taskObj instanceof TaskNetMessage) {
										TaskNetMessage msg = (TaskNetMessage) taskObj;
										sb.append(ConstantCode.getName(MessageTypes.class, msg.getMessageType()));
									}

									log.error("rtask=" + returnSectionQueue.size() + " task=" + taskQueue.size()
											+ " " + taskObj.getClass().getSimpleName() + "(" + sb.toString()
											+ ").procTask() spend time too long " + spendTime + " ms");
								}
							}

						} catch (Throwable t) {
							if (log.isErrorEnabled()) {
								log.error(GameUtility.getCurMethodName() + ": catch error 2", t);
							}
							//為避免對server core的影響,目前logException只應用在mobile module
							//if(MobileModule.isOn) {
							//	taskObj.logException(t);
							//} else 
							//{
								throw t;
							//}
						}
					}
				}
				
				if (threadDone == true) {
					
					if(state == MODULE_STATE.WAIT_TO_CLOSE)
					{
						state = MODULE_STATE.CLOSED;
						return;
					}
					else
						break;
				}
				
				if(state == MODULE_STATE.WAIT_TO_CLOSE)
				{
					state = MODULE_STATE.CLOSED;
					return;
				}
				else
				{
					synchronized(mainThreadSignal) {
							mainThreadSignal.wait(1000);
					}
					
					if(state == MODULE_STATE.WAIT_TO_CLOSE)
					{
						state = MODULE_STATE.CLOSED;
						return;
					}					
				}	
			} catch(Throwable e) {
				// 線程 catch 全部
				if (log.isErrorEnabled()) {
					log.error(GameUtility.getCurMethodName() + ": catch error 3", e);
				}
			}
		}
		if (log.isInfoEnabled()) {
			log.info("Thread Done!");
		}
	}
}
